package com.louzhu.gulimall.product.web;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.louzhu.gulimall.product.entity.CategoryEntity;
import com.louzhu.gulimall.product.service.CategoryService;
import com.louzhu.gulimall.product.vo.Catelog2Vo;
import org.redisson.api.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 首页控制器
 */
@Controller
public class IndexController {

    @Autowired
    private CategoryService categoryService;

    @Autowired
    private RedissonClient redisson;

    @Autowired
    private StringRedisTemplate redisTemplate;

    /**
     * 跳转至首页
     */
    @GetMapping({"/","/index.html"})
    public String indexPage(Model model){
        // 1 查出所有的一级分类
        List<CategoryEntity> categorys = categoryService.getFirstLevelCatelog();
        // 2 将返回数据放入页面请求域
        model.addAttribute("categorys",categorys);
        // 3 页面跳转
        // 默认前缀 classpath:/templates/
        // 默认后缀 .html
        // 视图解析器会自动根据默认的配置，将路径前缀后缀拼接上，即：/templates/index.html
        return "index";
    }

    /**
     * 获取三级分类JSON数据
     * index/json/catalog.json
     */
    @ResponseBody // 表明不是跳转页面，将数据以JSON方式返回页面
    @GetMapping("index/json/catalog.json")
    public  Map<String, List<Catelog2Vo>> getCatalogJson(){
        Map<String, List<Catelog2Vo>> map = categoryService.getCatalogJson();
        return map;
    }

    /**
     * Redisson 闭锁 测试
     *
     * 业务场景模拟闭锁：学校放假，关闭大门之前要等待每个班的同学都走完才能关闭大门
     */
    @ResponseBody
    @GetMapping("/lockDoor")
    public String lockDoor() throws InterruptedException {
        RCountDownLatch countDownLatch = redisson.getCountDownLatch("door");
        // 假设有5个班：五个闭锁
        countDownLatch.trySetCount(5L);
        // 等待每个班的人都走完（等待所有闭锁都完成）
        countDownLatch.await();
        // 每个班的人都走完（所有闭锁都完成）
        return "锁门。。。";
    }

    @ResponseBody
    @GetMapping("/gogogo/{id}")
    public String gogogo(@PathVariable("id") Long id){
        RCountDownLatch countDownLatch = redisson.getCountDownLatch("door");
        // 每走完一个班的学生，闭锁计数减一
        countDownLatch.countDown();
        return id + "班的人走完了。。。";
    }

    /**
     * Redisson信号量测试
     * 停车位统计业务模拟信号量
     * 来一辆车减一 走一辆车加一
     */
    @ResponseBody
    @GetMapping("/park")
    public String park() throws InterruptedException {
        RSemaphore park = redisson.getSemaphore("park");
        // 停车 占一个车位
        // 如果信号量不足，就会阻塞
        // park.acquire();
        // 如果信号量不足就返回false
        boolean tryAcquire = park.tryAcquire();
        if(tryAcquire){
            // 信号量足够 执行业务
            return Thread.currentThread().getId() + "停车成功";
        }else {
            return Thread.currentThread().getId() + "停车失败，剩余车位不足";
        }

    }
    @ResponseBody
    @GetMapping("/go")
    public String go() {
        RSemaphore park = redisson.getSemaphore("park");
        // 开走 释放一个车位
        park.release();
        return Thread.currentThread().getId() + "开走";
    }



    /**
     * Redisson读写锁测试
     * 写数据
     */
    @ResponseBody
    @GetMapping("/write")
    public String writeValue(){
        // 读写共用一个锁
        RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
        // 写锁
        RLock wLock = lock.writeLock();
        // 改数据 加写锁
        wLock.lock();
        System.out.println(Thread.currentThread().getId() + "加写锁成功");
        // 执行写数据操作业务
        String s = "";
        try {
            s = UUID.randomUUID().toString();
            Thread.sleep(10000);
            redisTemplate.opsForValue().set("writeValue",s);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            // 解锁
            wLock.unlock();
            System.out.println(Thread.currentThread().getId() + "写锁释放");

        }
        return s;
    }

    /**
     * Redisson读写锁测试
     * 读数据
     * @return
     */
    @ResponseBody
    @GetMapping("/read")
    public String readValue(){
        // 读写共用一个锁
        RReadWriteLock lock = redisson.getReadWriteLock("rw-lock");
        // 读锁
        RLock rLock = lock.readLock();
        // 读数据加读锁
        rLock.lock();
        System.out.println(Thread.currentThread().getId() + "加读锁成功");
        // 执行读数据操作业务
        String s = "";
        try{
            Thread.sleep(10000);
            s = redisTemplate.opsForValue().get("writeValue");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            // 手动解锁
            rLock.unlock();
            System.out.println(Thread.currentThread().getId() + "读锁释放");
        }

        return s;
    }


    /**
     * Redisson可重入锁测试
     * @return
     */
    @ResponseBody
    @GetMapping("/hello")
    public  String hello(){
        /*
        指定锁名称，获取锁，只要锁名称相同，那就是同一个锁
         */
        RLock lock = redisson.getLock("my-lock");
        /*
        加锁：阻塞式等待
         */
        // 不指定过期时间，默认30秒
        // lock.lock();
        // 10秒后锁过期自动删除解锁
        lock.lock(10, TimeUnit.SECONDS);
        System.out.println(Thread.currentThread().getId() + "加锁成功");
        try{
            // 业务代码
            // 线程睡眠30秒测试
            Thread.sleep(30000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            /*
            手动解锁
             */
            lock.unlock();
            System.out.println(Thread.currentThread().getId()  + "解锁成功");
        }
        return "hellow";
    }




}
